#!/usr/bin/env python3
"""
演示如何在Python中打包包含位域的C结构体
"""

import struct


def pack_zq_cmd_mem_rw_pkg(type_val, rw_val, err_val, res_val, len_val, addr_val, data_bytes):
    """
    打包ZqCmdMemRWPkg结构体
    
    C结构体定义:
    typedef struct {
        uint32_t type:3;        // 0 - ram; 1 - ram tmp file(<=10K); 2 - data flash; 3 - code flash; 
        uint32_t rw:2;          // 0 - read; 1 - write; 2,3 - 用户自定义扩展
        uint32_t err:3;         // 0 - no error; 1 - out of bounds; 2 - busy; 7 - unknown error
        uint32_t res:8;         // 
        uint32_t len:16;        // read/write len
        uint32_t addr;          // read/write start addr - must align 4 bytes
        uint8_t data[0];        // data R/W or verify
    } ZqCmdMemRWPkg;
    
    Args:
        type_val: type字段值 (3位)
        rw_val: rw字段值 (2位)
        err_val: err字段值 (3位)
        res_val: res字段值 (8位)
        len_val: len字段值 (16位)
        addr_val: addr字段值 (32位)
        data_bytes: data字段的字节数据
        
    Returns:
        bytes: 打包后的数据
    """
    
    # 验证位域值范围
    if not (0 <= type_val <= 0b111):          # 3位
        raise ValueError("type_val must be between 0 and 7")
    if not (0 <= rw_val <= 0b11):             # 2位
        raise ValueError("rw_val must be between 0 and 3")
    if not (0 <= err_val <= 0b111):           # 3位
        raise ValueError("err_val must be between 0 and 7")
    if not (0 <= res_val <= 0b11111111):      # 8位
        raise ValueError("res_val must be between 0 and 255")
    if not (0 <= len_val <= 0xFFFF):          # 16位
        raise ValueError("len_val must be between 0 and 65535")
    
    # 手动构建第一个32位字段，包含所有位域
    # 位域在little-endian系统中通常是从低位到高位排列
    first_field = (
        (type_val & 0b111) |                 # bits 0-2: type
        ((rw_val & 0b11) << 3) |             # bits 3-4: rw
        ((err_val & 0b111) << 5) |           # bits 5-7: err
        ((res_val & 0b11111111) << 8) |      # bits 8-15: res
        ((len_val & 0xFFFF) << 16)           # bits 16-31: len
    )
    
    # 打包结构体
    # < 表示小端序
    # I 表示32位无符号整数
    # I 表示addr字段
    # {}s 表示可变长度的数据字段
    format_str = '<II{}s'.format(len(data_bytes))
    packed_data = struct.pack(format_str, first_field, addr_val, data_bytes)
    
    return packed_data


def unpack_zq_cmd_mem_rw_pkg(packed_data):
    """
    解包ZqCmdMemRWPkg结构体
    
    Returns:
        tuple: (type, rw, err, res, len, addr, data)
    """
    # 先解包前两个固定字段
    first_field, addr = struct.unpack('<II', packed_data[:8])
    
    # 从第一个字段中提取位域
    type_val = first_field & 0b111                    # bits 0-2
    rw_val = (first_field >> 3) & 0b11                # bits 3-4
    err_val = (first_field >> 5) & 0b111              # bits 5-7
    res_val = (first_field >> 8) & 0b11111111         # bits 8-15
    len_val = (first_field >> 16) & 0xFFFF            # bits 16-31
    
    # 提取数据部分
    data = packed_data[8:]
    
    return (type_val, rw_val, err_val, res_val, len_val, addr, data)


# 示例用法
if __name__ == "__main__":
    # 示例数据
    type_val = 2      # data flash
    rw_val = 1        # write
    err_val = 0       # no error
    res_val = 0       # reserved
    len_val = 10      # 10字节数据
    addr_val = 0x1000 # 地址
    data_bytes = b"HelloWorld"  # 10字节数据
    
    # 打包
    packed = pack_zq_cmd_mem_rw_pkg(type_val, rw_val, err_val, res_val, len_val, addr_val, data_bytes)
    print(f"Packed data: {packed.hex()}")
    
    # 解包
    unpacked = unpack_zq_cmd_mem_rw_pkg(packed)
    print(f"Unpacked: type={unpacked[0]}, rw={unpacked[1]}, err={unpacked[2]}, "
          f"res={unpacked[3]}, len={unpacked[4]}, addr=0x{unpacked[5]:08X}, data={unpacked[6]}")